Коллекции в Java
Коллекции в Java
Что такое коллекция
★ Коллекции в Java – сложный инструмент для работы с данными, который позволяет хранить, обрабатывать и манипулировать группами объектов.
Collection — это интерфейс в java.util, который задаёт общий контракт для всех коллекций, хранящих группы объектов. Через него определяются ключевые операции: добавление и удаление элементов, проверка их наличия, очистка коллекции, получение размера и итерация.
Фреймворк коллекций Java (java.util) предоставляет унифицированную архитектуру для хранения и манипулирования группами объектов. Основные компоненты:
Collection (интерфейс)
├── List (интерфейс)
│ ├── ArrayList (класс)
│ ├── LinkedList (класс)
│ └── Vector (класс)
├── Set (интерфейс)
│ ├── HashSet (класс)
│ └── TreeSet (класс)
└── Queue (интерфейс)
└── PriorityQueue (класс)
Основные реализации — List, Set и Queue.
Сам интерфейс не потокобезопасен, но его можно обернуть в синхронизированную версию через Collections.synchronizedCollection() или использовать классы из java.util.concurrent. Collection работает с дженериками, что обеспечивает типобезопасность и упрощает работу с элементами.
Важно помнить, что Map не наследуется от Collection, так как представляет пары ключ–значение и имеет свою иерархию.
Collection
Collection – корневой интерфейс, представляющий собой группу элементов (объектов). Он определяет базовые операции над набором данных: добавление, удаление, проверка наличия, размер и т.д.
Данных бывает много, и в памяти их как-то надо структурировать.
Упорядочить – вывод списка пользователей в том порядке, в котором они регистрировались (ArrayList, LinkedHashMap).
Исключать дубликаты – например, загрузка данных из разных источников и удаление повторяющихся записей (HashSet, LinkedHashSet).
Сортировать – рейтинг игроков, сортировка товаров по цене (TreeSet, TreeMap).
Хранить пары «ключ-значение» - кэширование результатов вычислений, например (HashMap, TreeMap).
Работать с очередями и приоритетами – обработка задач в фоновых потоках (PriorityQueue, Deque).
Коллекции активно используются в веб-приложениях, бизнес-логике (валидация, фильтрация), алгоритмах (поиск, сортировка), параллелизме (concurrent коллекции).
У этого интерфейса есть основные подынтерфейсы:
- List – упорядоченная коллекция с дубликатами;
- Set – неупорядоченная колелкция без дубликатов;
- Queue – очередь, используется для обработки элементов по принципу FIFO (First In, First Out, первый зашел - первый вышел);
- Deque – двусторонная очередь.
- Map не является частью иерархии Collection, но часто рассматривается вместе с ними.
List
List – упорядоченные списки. Реализует интерфейс List<E>. Поддерживает индексацию и дублирование элементов. Существуют реализации через ArrayList, LinkedList, Vector.
ArrayList
ArrayList – реализован на основе динамического массива (Array – это массив). Имеет быстрый доступ по индексу, медленную вставку/удаление в середине.
ArrayList, как можно понять из слова Array, основан на обычном массиве (Object[]). При создании выделяется массив фиксированного начального размера (по умолчанию 10).
При добавлении элемента сверх вместимости создается новый массив большего размера (обычно в 1.5 раза) и копируются старые данные.
Пример:
List<String> list = new ArrayList<>();
list.add("Java");
Операции:
add(value)— добавление в конец;add(index, value)— вставка в середину;get(index)— чтение по индексу;set(index, value)— замена по индексу;remove(index)— удаление.
Давайте рассмотрим разницу между ArrayList и LinkedList:
// Демонстрация работы ArrayList (быстрый доступ по индексу)
import java.util.ArrayList;
import java.util.List;
public class ArrayListExample {
public static void main(String[] args) {
// Создаем список с начальной емкостью
List<String> users = new ArrayList<>();
// Добавление элементов
users.add("Ivan");
users.add("Maria");
users.add("Alex");
// Быстрый доступ по индексу O(1)
System.out.println("Первый пользователь: " + users.get(0));
// Вставка элемента в середину (медленная операция O(n))
users.add(1, "NewUser");
// Удаление элемента по индексу
users.remove(0);
// Итерация через цикл for (доступен только для List)
for (int i = 0; i < users.size(); i++) {
System.out.println(users.get(i));
}
}
}
ArrayList — выбор по умолчанию (80% случаев). Использовать в принципе можно всегда, особенно если в основном происходит чтение по индексу, часто проходим по списку в цикле, или не знаем, что выбрать.
List<String> names = new ArrayList<>();
names.add("Alice"); // быстро
names.add("Bob");
String name = names.get(0); // моментально
ArrayList занимает меньше памяти на элемент (только ссылка + маленький overhead массива). LinkedList значительно больше памяти на элемент: каждый узел хранит 3 ссылки (предыдущий, следующий, данные) + объект Node. Для 1 млн элементов разница может быть в 5-10 раз!
При добавлении 11-го элемента в список с capacity=10:
- Создается новый массив на 15 элементов.
- Копируются все 10 старых. Это дорого, но случается редко (амортизированно
O(1)).
LinkedList
LinkedList – реализован как двусвязный список. Быстрая вставка/удаление, медленный доступ по индексу. Пример:
List<Integer> numbers = new LinkedList<>();
numbers.add(10);
LinkedList реализован как двусвязный список узлов (Node). Каждый узел хранит данные, ссылку на предыдущий и следующий узел.
Как устроен LinkedList внутри? Упрощённо, как-то так:
private static class Node<E> {
E item; // данные
Node<E> next; // ссылка на следующий узел
Node<E> prev; // ссылка на предыдущий узел
}
Пример:
[null] ← [Узел 1] ↔ [Узел 2] ↔ [Узел 3] → [null]
│ │ │
"Кошка" "Собака" "Попугай"
- Первый узел (head):
prev = null; - Последний узел (tail):
next = null; - Каждый узел хранит три вещи: данные + две ссылки.
ArrayList при удалении из начала:
list.remove(0); // Удалит первый элемент и сдвинет все остальные — О(n)
LinkedList при get(index):
list.get(250000); // LinkedList пройдет 250000 узлов от начала — очень медленно!
Не требует непрерывного блока памяти — узлы могут быть разбросаны по куче.
Операции:
add(value)— добавление в конец;add(index, value)— вставка в середину;get(index)— чтение по индексу;set(index, value)— замена по индексу;remove(index)— удаление.
LinkedList является ускоспециализированной структурой, поэтому её использовать стоит, если количество операций get(index) минимально или отсутствует, если часто вставляют или удаляют элементы в середине или начале списка доступными итераторами.
Vector
Vector (устаревший) – похож на ArrayList, но синхронизированный, медленнее из-за блокировок. В современных приложениях вместо Vector используют Collections.synchronizedList() или CopyOnWriteArrayList. Пример:
List<String> legacyList = new Vector<>();
Set
Set – набор уникальных элементов. Интерфейс Set<E> гарантирует отсутствие дубликатов. Существуют реализации через HashSet, LinkedHashSet, TreeSet.
давайте рассмотрим разницу между ними:
// Демонстрация различий между реализациями Set
import java.util.*;
public class SetExamples {
public static void main(String[] args) {
// HashSet: порядок не гарантируется, дубликаты запрещены
Set<String> hashSet = new HashSet<>();
hashSet.add("Java");
hashSet.add("Python");
hashSet.add("Java"); // Этот элемент будет проигнорирован
System.out.println("HashSet размер: " + hashSet.size()); // Выведет 2
// LinkedHashSet: сохраняет порядок вставки
Set<String> linkedSet = new LinkedHashSet<>();
linkedSet.add("First");
linkedSet.add("Second");
linkedSet.add("Third");
System.out.println("LinkedHashSet порядок: " + linkedSet); // [First, Second, Third]
// TreeSet: сортирует элементы естественным образом
Set<Integer> treeSet = new TreeSet<>();
treeSet.add(50);
treeSet.add(10);
treeSet.add(30);
System.out.println("TreeSet отсортирован: " + treeSet); // [10, 30, 50]
}
}
HashSet
HashSet хранит элементы в неопределённом порядке, использует хеш-таблицу, обладает быстрой вставкой, поиском и удалением. Пример:
Set<String> set = new HashSet<>();
set.add("Apple");
LinkedHashSet
LinkedHashSet сохраняет порядок вставки элементов. Это комбинация HashSet и связанного списка. Пример:
Set<String> orderedSet = new LinkedHashSet<>();
orderedSet.add("First");
TreeSet
TreeSet хранит элементы в отсортированном порядке, реализован на основе красно-чёрного дерева. Пример:
Set<Integer> sortedSet = new TreeSet<>();
sortedSet.add(5);
Map
Map – словарь (ключ и значение). Ключи уникальны.
Map (интерфейс)
├── HashMap (класс) - неупорядоченное отображение
├── LinkedHashMap (класс) - упорядоченное по вставке
├── TreeMap (класс) - упорядоченное по ключу
└── Hashtable (класс) - синхронизированное отображение
Пример работы с ключами, значениями и порядком:
// Демонстрация работы Map и её реализаций
import java.util.*;
public class MapExamples {
public static void main(String[] args) {
// HashMap: быстрый доступ, порядок не гарантируется
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 87);
scores.put("Alice", 99); // Значение перезапишется
System.out.println("Значение Alice: " + scores.get("Alice")); // 99
// LinkedHashMap: сохраняет порядок вставки
Map<String, String> history = new LinkedHashMap<>();
history.put("Page1", "start");
history.put("Page2", "middle");
history.put("Page3", "end");
System.out.println("История (порядок вставки): " + history.keySet());
// TreeMap: сортировка по ключам
Map<Integer, String> days = new TreeMap<>();
days.put(3, "Wednesday");
days.put(1, "Monday");
days.put(2, "Tuesday");
System.out.println("Дни недели (по возрастанию ключей): " + days);
}
}
HashMap
HashMap – самая популярная реализация Map, позволяет один null в качестве ключа и несколько null в значениях, однако не гарантирует порядка.
Пример:
Map<String, Integer> map = new HashMap<>();
map.put("one", 1);
TreeMap
TreeMap – реализован на основе красно-чёрного дерева. Хранит пары в отсортированном по ключам порядке. Пример:
Map<String, Integer> sortedMap = new TreeMap<>();
sortedMap.put("banana", 2);
Hashtable
Hashtable – устаревшая, синхронизированная версия HashMap. Не позволяет использовать null в ключах и значениях. Вместо Hashtable лучше использовать ConcurrentHashMap или Collections.synchronizedMap(). Пример:
Map<String, String> legacyMap = new Hashtable<>();
legacyMap.put("key", "value");
LinkedHashMap
LinkedHashMap сохраняет порядок вставки элементов и полезен, когда нужно сохранять историю изменений. Пример:
Map<String, String> history = new LinkedHashMap<>();
history.put("first", "start");
Queue
Queue – очереди. Они предназначены для обработки элементов по принципу FIFO (First In – First Out). Бывают как PriorityQueue или Deque. PriorityQueue – элементы извлекаются в порядке приоритета (по значению или с помощью компаратора). Не поддерживает null. Пример:
Queue<Integer> queue = new PriorityQueue<>();
queue.offer(3);
queue.poll(); // 3 (если минимальный)
Пример работы принципов LIFO и FIFO:
// Демонстрация работы очередей и двусторонних очередей
import java.util.*;
public class QueueExamples {
public static void main(String[] args) {
// PriorityQueue: извлечение по приоритету (минимальный элемент первым)
Queue<Integer> priorityQueue = new PriorityQueue<>();
priorityQueue.offer(10);
priorityQueue.offer(2);
priorityQueue.offer(5);
System.out.println("Приоритетный элемент: " + priorityQueue.poll()); // 2
// Deque (ArrayDeque): работа как стек (LIFO) и очередь (FIFO)
Deque<String> deque = new ArrayDeque<>();
// Добавление в конец (как в очередь)
deque.offerLast("A");
deque.offerLast("B");
// Добавление в начало (как в стек)
deque.push("C");
System.out.println("Последний элемент: " + deque.peekLast()); // B
System.out.println("Первый элемент: " + deque.pop()); // C (удалено)
// Очистка очереди
while (!deque.isEmpty()) {
System.out.print(deque.poll() + " ");
}
}
}
Deque
Deque (Double Ended Queue) – можно добавлять или удалять элементы с обоих концов. Реализуется через ArrayDeque или LinkedList. Пример:
Deque<String> deque = new ArrayDeque<>();
deque.push("first");
deque.pop();
Давайте теперь разберём, когда что использовать.
Виды
| Тип | Когда использовать | Пример |
|---|---|---|
| ArrayList | Нужен быстрый доступ по индексу | Список пользователей, список товаров в корзине |
| LinkedList | Частые вставки или удаления в начале или середине | Реализация очереди, стека, история действий (undo/redo) |
| HashSet | Нужны уникальные элементы, порядок не важен | Проверка уникальности email, фильтрация дубликатов из базы данных |
| LinkedHashSet | Нужна уникальность и сохранение порядка вставки | История посещённых страниц, удаление дубликатов с сохранением порядка |
| TreeSet | Нужен отсортированный набор | Рейтинг игроков, очередь задач с приоритетом |
| HashMap | Обычный словарь, скорость важнее порядка | Кэширование объектов по ключу, хранение параметров конфигурации |
| LinkedHashMap | Нужен порядок вставки | Лог-файл с записями в порядке добавления, кэш LRU (Least Recently Used) |
| TreeMap | Нужен отсортированный словарь | Рейтинг студентов, поиск значений в диапазоне (например, дат) |
| PriorityQueue | Нужна очередь с приоритетом | Система обслуживания в банке, планировщик задач |
| Vector / Hashtable | Устаревшие, лучше избегать в новых проектах | Поддержка устаревшего кода, многопоточные приложения без современных альтернатив |
Общие методы коллекций
Все коллекции имеют общие методы, но не все реализации поддерживают все операции. Давайте соберём важнейшие:
add(E e)добавляет элемент в коллекцию, используется в List, Set, Queue, для Set игнорирует дубликаты.remove(Object o)удаляет указанный элемент, используется во всех коллекциях, возвращает true, если элемент был найден.contains(Object o)проверяет наличие элемента, использует equals() и hashCode().containsKey()иcontainsValue()проверет наличие элемента для Map;get(int index)получает элемент по индексу, используется только в List, причем в ArrayList – делает быстро, в LinkedList – медленно.put(K key, V value)добавляет пару ключ-значение, используется в Map, перезаписывает значение, если ключ уже есть.get(Object key)получает значение по ключу, используется в Map, возвращает null, если ключ не найден.poll()извлекает и удаляет первый элемент, используется в Queue, Deque, возвращает null, если очередь пуста.offer(E e)добавляет элемент в очередь, используется в Queue, возвращает false, если не удалось добавить.peek()возвращает, но не удаляет первый элемент, используется в Queue, полезно для проверки перед извлечением.
Примеры:
// ArrayList
List<String> list = new ArrayList<>();
list.add("Java");
list.add(0, "Hello"); // вставка в начало
System.out.println(list.get(1)); // Java
// HashSet
Set<Integer> uniqueNumbers = new HashSet<>();
uniqueNumbers.add(1);
uniqueNumbers.add(1); // дубликат игнорируется
System.out.println(uniqueNumbers.contains(1)); // true
// HashMap
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 90);
System.out.println(scores.get("Alice")); // 90
// PriorityQueue
Queue<Integer> queue = new PriorityQueue<>();
queue.offer(5);
queue.offer(3);
System.out.println(queue.poll()); // 3 (минимальный элемент)
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). JDK (Java Разработка Kit) — полный комплект разработчика. Включает — Компилятор javac для преобразования исходного кода в байт-код, Виртуальную машину JVM для выполнения байт-кода, Стандартные… Фундамент для начинающего программиста - что повторить, как работать, чего ожидать. Набор советов, правил, принципов и обычаев в разработке на этом языке. Use-after-free — это обращение к участку памяти после его освобождения. Программа продолжает использовать указатель на объект, память которого уже возвращена системе управления памятью. Библиотеки, фреймворки, инструменты сборки, тестирования, развёртывания и мониторинга. Что такое пакет и пакетная структура, как собираются проекты на Java. Справочник-шпаргалка по конфигурациям в Java — типы, синтаксис, стандартная библиотека, типовые паттерны. Не заменяет пошаговое обучение. Учебный курс — раздел. Гайд по установке и настройке с написанием первой программы и её запуском. Примеры простых и полезных консольных приложений с демонстрацией концепций языка. Кавычки, точки, запятые, скобки и прочие знаки препинания. Это полный справочник всех ключевых слов языка Java, включая основные, контекстные и зарезервированные слова. Набор функций, которые включены в стандартную библиотеку языка.Основы языка Java
Что требуется знать перед началом изучения языка программирования Java
Рекомендации по разработке на Java
История языка Java
Экосистема Java-приложений
Структура и сборки Java-проектов
Справочник по конфигурациям в Java
Первая программа на Java
Простые приложения на Java
Синтаксис и пунктуация в Java
Ключевые слова в Java
Встроенные функции и методы Java